프로세스/스레드 동기화

프로세스 동기화

동기화란 병렬적으로 수행되는 작업들에 대해 자원에의 접근에 대한 순서를 정하는 과정을 말한다. 여러개의 프로세스나 쓰레드의 경우 동시에 특정 자원에 대한 접근이 발생할 수 있는데 이 과정에서 자원에 대해 동시 접근을 허용해 버린다면 예기치 못한 결과를 발생시킬 수 있다.

1
2
3
4
5
6
7
int x = 10;

public int cal(int a)
{
x = a+1;

}

Thread A와 Thread B가 전역변수 x에 대해 cal(x)를 동시에 수행했다고 가정해보자 사용자는 cal(x)를 두번 호출해서 12의 결과를 얻기를 원했다 하지만 Thread의 수행 순서는 예측할수 없기 때문에 Thread A와 Thread B가 모두 cal(x)를 호출하여 전역 변수 x의 을 자신의 local 변수 a에 복사하였다. 이 경우 Thread A와 Thread B는 10에 대하여 +1한값을 x에 집어넣기 때문에 x에는 최종적으로 11의 값이 들어가게 된다.

-> 두 쓰레드의 실행 순서가 보장되지 않았기 때문에 예상한 결과와 다른 결과를 나타내었다.

이렇게 예상치 못한 결과에 대하여 방지하고 한정된 자원에 대해 접근 순서를 보장하는 것을 동기화라고 한다.

임계구역

임계 구역 (Critical Section)이란 동시에 접근하는 것을 제한해야 하는 구역이다. 즉 쓰레드나 프로세스에 의해 한번에 한 프로세스 or 스레드가 접근하기를 원하는 구역이다. Mutex의 경우 락을 걸고 락을 푸는 사이의 영역이 임계구역이 된다. 임계구역은 자원에 대한 접근이나 연산이 동시에 이루어지지 않아야 하는 구역에 대하여 설정한다.

##Mutex vs SemaPhore

뮤텍스와 세마포어는 동기화를 위한 도구이다. 뮤텍스와 세마포어는 흔히들 말하는 화장실에 들어가는 키라고 말할 수 있다. 화장실에는 한번에 한명밖에 들어갈 수 없기 때문에 키를 획득한 사람만 들어갈 수가 있다.

뮤텍스와 세마포어의 차이라 함은 이 키에 대한 개수에서 차이가 있다. Mutex는 키가 1개이기 때문에 화장실에 한번에 한명 들어갈 수 있지만 세마포어는 키가 여러개여서 여러명이 들어갈 수 있다.

뮤텍스와 세마포어를 구현하는 방식은 Busy - wait를 통해 키를 획득할때 까지 빈 while문을 실행하는 방법과 프로세스의 상태를 sleep으로 전환시킨 뒤 실행해야 할 때 wake up 시켜 ready queue에 집어넣는 방법이 있다.

Busy - waiting
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int key = 0;
int x = 10;
public void lock()
{
while(key < 0){}
key--;
}
public void unlock()
{
key = 0;
}

public void calc(int a)
{
lock();
x = a+1;
unlock();
}

Busy -waiting은 key를 획득하지 못하면 while문을 계속해서 돌게 된다. 위의 코드에서는 key의 값이 0일때 임계영역에 들어갈 수 있다. 하지만 쓰레드는 순서에 대한 보장이 없으므로 key 값을 읽었을 때 동시에 여러 스레드가 0값을 읽을 가능성이 있다. 이에 대한 해결방법은 하드웨어적인 방법을 이용한 test - and - set 명령어를 사용하는 것이다. test and set은 변수를 읽는 중에 다른 쓰레드가 덮어 썼는지 확인하고 다시 읽기 때문에 이 문제를 해결할 수 있으며 많은 뮤텍스 세마포어가 test and set을 이용하여 구현한다.

Sleep - wake up
1
2
3
4
5
typedef struct
{
int value;
struct process *L;
}semaphore;

Sleep - wake up 방식은 위의 방식에서 while문 대신 해당 프로세스를 sleep 시킨뒤 sleep 대기 큐에 집어넣고 완료하면 꺼내는 방식을 이용해 구현한다.

Busy-wait 방식과 Sleep wait 방식의 효율성을 비교하면 평균적으로 Sleep wait 방식이 더욱 좋다. Busy- wait의 경우 기다리는 동안 while문으로 회전하기 때문에 cpu의 쓸데 없는 사용이 생겨나게 된다. 하지만 Sleep wait 방식의 경우 프로세스의 상태를 변경시키고 ready queue에 넣기 때문에 wait queue에서 ready queue로 비용이 든다. 따라서 cpu 사용량이 짧을경우 busy-wait 방식이 더욱 빠르다고 한다.

공유하기